package games.mapacman.client;

import games.mapacman.common.Constants;
import games.mapacman.common.Dot;
import games.mapacman.common.EatenSign;
import games.mapacman.common.Fruit;
import games.mapacman.common.Powerpill;
import games.mapacman.common.ScoreSign;
import games.mapacman.common.Superdot;
import games.mapacman.common.ZoneChangePoint;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Point;
import java.awt.Transparency;
import java.awt.geom.Point2D;
import java.awt.image.BufferStrategy;
import java.util.Vector;

import javax.swing.JPanel;

import marauroa.common.Log4J;
import marauroa.common.game.RPObject;

/**
 * This class is an abstraction of the game screen, so that we can think of it
 * as a window to the world, we can move it, place it and draw object usings
 * World coordinates. This class is based on the singleton pattern.
 */
public class GameScreen {

    private static final marauroa.common.Logger logger = Log4J.getLogger(GameScreen.class);
    /** One unit is 24 pixels */
    public final static int PIXEL_SCALE = 24;
    /** Minimum distance from player to screen border in world units */
    public final static int MIN_DISTANCE = 5;
    /** The amount of pixels screen moves each nextFrame() */
    public final static int PIXEL_MOVES = 9;
    /**
     * The amount of frames that should be scrolled even if the player is still
     * placed in the limit
     */
    public final static int SCROLL_MORE = 7;
    /** how many Pixels should a item between 2 worldunits move per frame */
    public double movePixelsPerFrame = 8d;
    private BufferStrategy strategy;
    private Graphics2D g;
    /** Actual rendering position of the leftmost top corner in world units */
    private double x, y;
    /** Actual speed of the screen */
    private double dx, dy;
    /** Actual size of the screen in pixels */
    private int sw, sh;
    /** Actual size of the world in world units */
    private int ww, wh;
    private Images ImageList;
    private RPObject myPlayer;
    private String myPlayerName;
    private int myScore;
    private String highestPlayer;
    private int highestScore;
    // to paint the first 5 frames complete
    private int paintCounter = -5;
    private int[][] walls;
    private Dot[][] dots;
    private static GameScreen screen;
    private Sprite[] sprite_wall;
    private Sprite wall_sprite;
    private Vector<Sprite> sprite_mplayer;
    private Vector<Sprite> sprite_oplayer;
    private Vector<Sprite> sprite_pplayer;
    private Sprite sprite_dot;
    private Sprite sprite_superdot;
    private Vector<Sprite> sprite_fruit;
    private Sprite sprite_powerpill;
    private Sprite sprite_zonechange;
    private Vector<Sprite> sprite_EatenSprite;
    private Vector<Sprite> sprite_GhostR;
    private Vector<Sprite> sprite_GhostG;
    private Vector<RPObject> Players;
    private Vector<RPObject> Ghosts;
    private Vector<EatenSign> EatenSigns;
    private Vector<ScoreSign> ScoreSigns;
    private Vector<String> ChatMessages;
    private Vector<ZoneChangePoint> zoneChangePoints;
    private int scrollInt = 0;
    private boolean scrolledInLastTurn = false;

    /** Create a screen with the given width and height */
    public static void createScreen(BufferStrategy strategy, int sw, int sh,
            int wuWidth, int wuHeight, JPanel panel) {
        if (screen == null) {
            screen = new GameScreen(strategy, sw, sh, wuWidth, wuHeight, panel);
        }
    }

    /** Returns the GameScreen object */
    public static GameScreen get() {
        return screen;
    }

    private GameScreen(BufferStrategy strategy, int sw, int sh, int wuWidth,
            int wuHeight, JPanel panel) {

        // needed for splitting Images to multpile sprites
        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

        ChatMessages = new Vector<String>();
        zoneChangePoints = new Vector<ZoneChangePoint>();
        EatenSigns = new Vector<EatenSign>();
        ScoreSigns = new Vector<ScoreSign>();
        ww = wuWidth;
        wh = wuHeight;
        clear();

        this.sw = sw;
        this.sh = sh;
        // INIT IMAGES !!
        ImageList = new Images(panel);
        // Walls
        this.wall_sprite = new Sprite(ImageList.getImage("wall0"));
        this.sprite_wall = new Sprite[16];
        for (int i = 0; i <= 15; i++) {
            this.sprite_wall[i] = new Sprite(ImageList.getImage("wall" + i));
        }
        // Dots, Sueprdots, Powerpills
        this.sprite_dot = new Sprite(ImageList.getImage("dot"));
        this.sprite_superdot = new Sprite(ImageList.getImage("superdot"));
        this.sprite_powerpill = new Sprite(ImageList.getImage("powerpill"));

        // Fruits
        this.sprite_fruit = new Vector<Sprite>();
        Sprite tempSprite = new Sprite(ImageList.getImage("fruits"));
        for (int i = 0; i <= 13; i++) {
            Image image = gc.createCompatibleImage(PIXEL_SCALE, PIXEL_SCALE,
                    Transparency.BITMASK);
            tempSprite.draw(image.getGraphics(), 0, 0, i * PIXEL_SCALE, 0);
            sprite_fruit.add(new Sprite(image));
        }

        // KILLed Sprite
        this.sprite_EatenSprite = new Vector<Sprite>();
        tempSprite = new Sprite(ImageList.getImage("eatensign"));
        for (int i = 0; i <= 2; i++) {
            Image image = gc.createCompatibleImage(PIXEL_SCALE, PIXEL_SCALE,
                    Transparency.BITMASK);
            tempSprite.draw(image.getGraphics(), 0, 0, i * PIXEL_SCALE, 0);
            sprite_EatenSprite.add(new Sprite(image));
        }

        // ZoneChangePoints
        this.sprite_zonechange = new Sprite(ImageList.getImage("zonechange"));
        // add Ghost sprites
        this.sprite_GhostR = new Vector<Sprite>();
        tempSprite = new Sprite(ImageList.getImage("GhostR"));
        for (int i = 0; i <= 9; i++) {
            Image image = gc.createCompatibleImage(PIXEL_SCALE, PIXEL_SCALE,
                    Transparency.BITMASK);
            tempSprite.draw(image.getGraphics(), 0, 0, i * PIXEL_SCALE, 0);
            sprite_GhostR.add(new Sprite(image));
        }

        this.sprite_GhostG = new Vector<Sprite>();
        tempSprite = new Sprite(ImageList.getImage("GhostG"));
        for (int i = 0; i <= 9; i++) {
            Image image = gc.createCompatibleImage(PIXEL_SCALE, PIXEL_SCALE,
                    Transparency.BITMASK);
            tempSprite.draw(image.getGraphics(), 0, 0, i * PIXEL_SCALE, 0);
            sprite_GhostG.add(new Sprite(image));
        }

        // add Player Images
        // for my Player
        this.sprite_mplayer = new Vector<Sprite>();
        tempSprite = new Sprite(ImageList.getImage("mplayer"));
        for (int i = 0; i <= 13; i++) {
            Image image = gc.createCompatibleImage(PIXEL_SCALE, PIXEL_SCALE,
                    Transparency.BITMASK);
            tempSprite.draw(image.getGraphics(), 0, 0, i * PIXEL_SCALE, 0);
            sprite_mplayer.add(new Sprite(image));
        }
        // and other Players
        this.sprite_oplayer = new Vector<Sprite>();
        tempSprite = new Sprite(ImageList.getImage("oplayer"));
        for (int i = 0; i <= 13; i++) {
            Image image = gc.createCompatibleImage(PIXEL_SCALE, PIXEL_SCALE,
                    Transparency.BITMASK);
            tempSprite.draw(image.getGraphics(), 0, 0, i * PIXEL_SCALE, 0);
            sprite_oplayer.add(new Sprite(image));
        }
        // and other Players
        this.sprite_pplayer = new Vector<Sprite>();
        tempSprite = new Sprite(ImageList.getImage("pplayer"));
        for (int i = 0; i <= 13; i++) {
            Image image = gc.createCompatibleImage(PIXEL_SCALE, PIXEL_SCALE,
                    Transparency.BITMASK);
            tempSprite.draw(image.getGraphics(), 0, 0, i * PIXEL_SCALE, 0);
            sprite_pplayer.add(new Sprite(image));
        }
        // ALL IMAGES ADDED

        x = y = 0;
        dx = dy = 0;
        g = (Graphics2D) strategy.getDrawGraphics();
        g.setBackground(Color.black);
        this.strategy = strategy;

        g.setColor(Color.black);
        g.fillRect(0, 0, sw, sh);
    }

    /** Prepare screen for the next frame to be rendered and move it if needed */
    public void nextFrame() {
        logger.debug("GameScreen::nextFrame");

        if (myPlayer != null) { // Do SCROLLING if necessary
            int PlayerX = myPlayer.getInt("x");
            int PlayerY = myPlayer.getInt("y");
            boolean scrolled = false;
            if (!isInScreen(PlayerX, PlayerY)) {
                place(PlayerX, PlayerY);
                paintCounter = 0;
            } else {
                if ((PlayerX >= (x - MIN_DISTANCE + sw / PIXEL_SCALE))
                        && (PlayerX < wh - MIN_DISTANCE)) {
                    dx = PIXEL_MOVES;
                    scrollInt = SCROLL_MORE;
                    scrolled = true;
                } else if ((PlayerX <= (x + MIN_DISTANCE)) && (x > 0)) {
                    dx = -PIXEL_MOVES;
                    scrollInt = SCROLL_MORE;
                    scrolled = true;
                }

                if ((PlayerY >= (y - MIN_DISTANCE + sh / PIXEL_SCALE))
                        && (PlayerY < wh - MIN_DISTANCE)) {
                    dy = PIXEL_MOVES;
                    scrollInt = SCROLL_MORE;
                    scrolled = true;
                } else if ((PlayerY <= (y + MIN_DISTANCE)) && (y > 0)) {
                    dy = -PIXEL_MOVES;
                    scrollInt = SCROLL_MORE;
                    scrolled = true;
                }
            }
            if (!scrolled) {
                if (scrollInt == 0) {
                    move(0, 0);
                } else {
                    scrollInt--;
                }
            }
            if (scrollInt > 0) {
                scrolledInLastTurn = true;
            }
        }

        // clear Area around Player and Ghosts
        for (RPObject object : Players) {
            repaintArea(object);
        }
        for (RPObject object : Ghosts) {
            repaintArea(object, 2);
        }

        // clear Area above ScoreSign
        for (ScoreSign sign : ScoreSigns) {
            repaintArea(sign.getX(), sign.getY() - 1, 0);
        }

        // draw ZoneChangePoints
        for (ZoneChangePoint point : zoneChangePoints) {
            point.draw(screen, sprite_zonechange);
        }

        // move and paint Players and Ghosts
        for (RPObject object : Players) {
            screen.movePlayer(object);
            int move = object.getInt("move");
            if (move < movePixelsPerFrame) {
                object.put("move", move + 1);
            }
        }
        for (RPObject object : Ghosts) {
            int move = object.getInt("move");
            if (move < movePixelsPerFrame) {
                object.put("move", move + 1);
            }
            screen.moveGhost(object);
        }

        // draw EatenSigns
        for (EatenSign sign : EatenSigns) {
            sign.draw(this);
        }

        // draw ScoreSigns
        for (ScoreSign sign : ScoreSigns) {
            sign.draw(this);
        }

        // create Info-panel at bottom
        g.setColor(Color.BLACK);
        g.fillRect(0, sh + 1, sw, 100);
        g.setColor(Color.RED);
        g.drawLine(0, sh, sw, sh);
        // draw Chat Text
        g.setColor(Color.white);
        int pos = 19;
        for (String chatText : ChatMessages) {
            g.drawString(chatText, 2, sh + pos);
            pos += 18;
        }

        // get Top Score
        for (RPObject object : Players) {
            int score = object.getInt("score");
            if (score > highestScore) {
                highestScore = score;
                highestPlayer = object.get("name");
            }
            if (object.get("name").equals(myPlayerName)) {
                myScore = score;
            }
        }

        // draw Scores and Chat Window
        g.setColor(Color.BLACK);
        g.fillRect(310, sh + 1, sw - 310, 41);
        g.setColor(Color.RED);
        g.drawLine(320, sh + 1, 320, sh + 40);
        g.drawLine(320, sh + 41, sw, sh + 41);
        g.drawLine(0, sh, sw, sh);
        g.setColor(Color.white);
        g.drawString("Your Score (" + myPlayerName + ") :" + myScore, 325,
                sh + 18);
        g.drawString("Top Score (" + highestPlayer + ") : " + highestScore,
                325, sh + 36);

        // empty Score
        myScore = 0;
        highestPlayer = "";
        highestScore = 0;

        // dispose current Frame
        g.dispose();
        strategy.show();
        g = (Graphics2D) strategy.getDrawGraphics();
        // DRAW STUFF FOR NEXT FRAME

        // clear Areas around some items ... EatenSigns at example ;)
        for (EatenSign sign : EatenSigns) {
            repaintArea(sign.getX(), sign.getY(), 0);
        }

        // remove EatenSigns if they have to disappear
        Vector<EatenSign> deleteEatenSigns = new Vector<EatenSign>();
        for (EatenSign sign : EatenSigns) {
            if (!sign.valid()) {
                deleteEatenSigns.add(sign);
            }
        }
        for (EatenSign sign : deleteEatenSigns) {
            EatenSigns.remove(sign);
        }
        // remove Score Signs if they have to disappear
        Vector<ScoreSign> deleteScoreSigns = new Vector<ScoreSign>();
        for (ScoreSign sign : ScoreSigns) {
            if (!sign.valid()) {
                deleteScoreSigns.add(sign);
            }
        }
        for (ScoreSign sign : deleteScoreSigns) {
            ScoreSigns.remove(sign);
        }

        if (((x + dx / PIXEL_SCALE >= -PIXEL_SCALE) && (dx < 0))
                || ((x + dx / PIXEL_SCALE + getWidth() <= ww) && (dx > 0))) {
            x += dx / PIXEL_SCALE;
        } else {
            dx = 0;
        }

        if (((y + dy / PIXEL_SCALE >= -PIXEL_SCALE) && (dy < 0))
                || ((y + dy / PIXEL_SCALE + getHeight() <= wh) && (dy > 0))) {
            y += dy / PIXEL_SCALE;
        } else {
            dy = 0;
        }

        // redraw everything except Players and Ghosts
        // paintCounter to make sure, that whole screen is repaint every 25
        // frames
        paintCounter--;
        if ((paintCounter < 0) || (dx != 0.0) || (dy != 0.0)) {
            if (paintCounter == 0) {
                paintCounter = 25;
            } else {
                paintCounter += 2;
            }
            paintScreen();
        }

        logger.debug("GameScreen::nextFrame");
    }

    private void repaintArea(RPObject object) {
        repaintArea(object, 1);

    }

    private void repaintArea(RPObject object, int border) {
        try {
            repaintArea(object.getInt("x"), object.getInt("y"), border);
        } catch (Exception e) {
        }

    }

    private boolean isInScreen(int x, int y) {
        if ((x < this.x - 1) || (x > this.x + sw / PIXEL_SCALE + 1)) {
            return false;
        }
        if ((y < this.y - 1) || (y > this.y + sh / PIXEL_SCALE + 1)) {
            return false;
        }
        // else
        return true;
    }

    /** Translate to screen coordinates the given world coordinate */
    public Point2D invtranslate(Point2D point) {
        double tx = (point.getX() - x) * PIXEL_SCALE;
        double ty = (point.getY() - y) * PIXEL_SCALE;
        return new Point.Double(tx, ty);
    }

    public double getWidth() {
        return sw / PIXEL_SCALE;
    }

    /** Returns screen height in world units */
    public double getHeight() {
        return sh / PIXEL_SCALE;
    }

    /**
     * Returns the Graphics2D object in case you want to operate it directly.
     * Ex. GUI
     */
    public Graphics2D expose() {
        return g;
    }

    /** Indicate the screen windows to move at a dx,dy speed. */
    public void move(double dx, double dy) {
        this.dx = dx;
        this.dy = dy;
    }

    /** Returns the x speed of the movement */
    public double getdx() {
        return dx;
    }

    /** Returns the y speed of the movement */
    public double getdy() {
        return dy;
    }

    /** Place the screen at the x,y position of world in world units. */
    public void place(double x, double y) {
        this.x = x;
        this.y = y;
    }

    /** Sets the world size */
    public void setMaxWorldSize(int width, int height) {
        ww = width;
        wh = height;
    }

    /** Translate to world coordinates the given screen coordinate */
    public Point2D translate(Point2D point) {
        double tx = (point.getX() / PIXEL_SCALE) + x;
        double ty = (point.getY() / PIXEL_SCALE) + y;
        return new Point.Double(tx, ty);
    }

    /** Draw a sprite in screen given its world coordinates */
    public void draw(Sprite sprite, Graphics2D g, double wx, double wy) {
        int sx = (int) ((wx - x) * PIXEL_SCALE + (PIXEL_SCALE - sprite.getHeight()) / 2);
        int sy = (int) ((wy - y) * PIXEL_SCALE + (PIXEL_SCALE - sprite.getWidth()) / 2);

        if (((sx >= -PIXEL_SCALE) && (sx < sw))
                && ((sy >= -PIXEL_SCALE) && (sy < sh))) {
            sprite.draw(g, sx, sy);
        }
    }

    /** Draw a sprite in screen given its world coordinates */
    public void draw(Sprite sprite, double wx, double wy) {
        draw(sprite, g, wx, wy);
    }

    public void drawString(String text, double wx, double wy, int scrollLeft,
            int scrollUp) {
        int sx = (int) ((wx - x) * PIXEL_SCALE);
        int sy = (int) ((wy - y) * PIXEL_SCALE);

        if (((sx >= -PIXEL_SCALE) && (sx < sw))
                && ((sy >= -PIXEL_SCALE) && (sy < sh))) {
            g.setColor(Color.YELLOW);
            g.drawString(text, sx + scrollLeft, sy + scrollUp);
        }
    }

    public Sprite createString(String text, Color textColor) {
        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        Image image = gc.createCompatibleImage(g.getFontMetrics().stringWidth(
                text), 16, Transparency.BITMASK);
        Graphics g2d = image.getGraphics();

        g2d.setColor(Color.black);
        g2d.drawString(text, -1, 9);
        g2d.drawString(text, -1, 11);
        g2d.drawString(text, 1, 9);
        g2d.drawString(text, 1, 11);

        g2d.setColor(textColor);
        g2d.drawString(text, 0, 10);
        return new Sprite(image);
    }

    public Sprite createTextBox(String text, int width, Color textColor,
            Color fillColor) {
        int lineLengthPixels = g.getFontMetrics().stringWidth(text);
        int numLines = (lineLengthPixels / width) + 1;

        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        Image image = gc.createCompatibleImage(
                ((lineLengthPixels < width) ? lineLengthPixels : width) + 4,
                16 * numLines, Transparency.BITMASK);

        Graphics g2d = image.getGraphics();
        g2d.setColor(fillColor);
        g2d.fillRect(0, 0, ((lineLengthPixels < width) ? lineLengthPixels
                : width) + 4, 16 * numLines);

        g2d.setColor(textColor);
        int lineLength = text.length() / numLines;
        for (int i = 0; i < numLines; i++) {
            String line = text.substring(i * lineLength, (i + 1) * lineLength);
            g2d.drawString(line, 2, i * 16 + 12);
        }

        return new Sprite(image);
    }

    public void addWall(int x, int y) {
        addWall(x, y, true);
    }

    public void addWall(int x, int y, boolean checkneihgbours) {
        int walltype = 0;
        if (checkneihgbours) {
            walls[x][y] = 0;
            if (walls[x + 1][y] > -1) {
                addWall(x + 1, y, false);
            }
            if (walls[x][y + 1] > -1) {
                addWall(x, y + 1, false);
            }
            if ((x > 0) && (walls[x - 1][y] > -1)) {
                addWall(x - 1, y, false);
            }
            if ((y > 0) && (walls[x][y - 1] > -1)) {
                addWall(x, y - 1, false);
            }
        }

        if ((y > 0) && (walls[x][y - 1] > -1)) {
            walltype += 1;
        }
        if (walls[x + 1][y] > -1) {
            walltype += 2;
        }
        if (walls[x][y + 1] > -1) {
            walltype += 4;
        }
        if ((x > 0) && (walls[x - 1][y] > -1)) {
            walltype += 8;
        }
        walls[x][y] = walltype;
    }

    public void drawWall(RPObject object) {
        int x = object.getInt("x");
        int y = object.getInt("y");
        drawWall(x, y);

    }

    public void drawWall(int x, int y) {
        if ((x < 0) || (y < 0)) {
            return;
        }
        if (isInScreen(x, y)) {
            if (walls[x][y] > -1) {
                draw(sprite_wall[walls[x][y]], g, x, y);
            }
        }

    }

    public void movePlayer(RPObject object) {
        int x = object.getInt("x");
        int y = object.getInt("y");

        if (!isInScreen(x, y)) {
            return;
        }

        int imgCounter = object.getInt("imgCounter");
        if (imgCounter == 2) {
            object.put("imgCounter", 0);
        } else {
            object.put("imgCounter", imgCounter + 1);
        }

        // check for collision
        checkCollisionWithWall(object);

        drawPlayer(object);

    }

    private void drawPlayer(RPObject object) {
        int imgCounter = object.getInt("imgCounter");
        int x = object.getInt("x");
        int y = object.getInt("y");

        Vector<Sprite> sprite_player;
        if (object.getInt("power") > 0) {
            sprite_player = sprite_pplayer;
        } else if (object == myPlayer) {
            sprite_player = sprite_mplayer;
        } else {
            sprite_player = sprite_oplayer;
        }
        switch (object.getInt("dir")) {
            case Constants.DIR_NORTH:
                draw(sprite_player.get((Constants.DIR_NORTH * 3) + imgCounter + 1),
                        g, x, y - (object.getInt("move") / movePixelsPerFrame));
                break;
            case Constants.DIR_SOUTH:
                draw(sprite_player.get((Constants.DIR_SOUTH * 3) + imgCounter + 1),
                        g, x, y + (object.getInt("move") / movePixelsPerFrame));
                break;
            case Constants.DIR_EAST:
                draw(sprite_player.get((Constants.DIR_EAST * 3) + imgCounter + 1),
                        g, x + (object.getInt("move") / movePixelsPerFrame), y);
                break;
            case Constants.DIR_WEST:
                draw(sprite_player.get((Constants.DIR_WEST * 3) + imgCounter + 1),
                        g, x - (object.getInt("move") / movePixelsPerFrame), y);
                break;
            case Constants.DIR_NONE:
                draw(sprite_player.get(0), g, x, y);
                break;
        }
        this.drawString(object.get("name"), x, y, 2, -2);

    }

    private void paintScreen() {
        g.setColor(Color.black);
        g.fillRect(0, 0, sw, sh);
        for (int i = 0; i < ww; i++) {
            for (int j = 0; j < wh; j++) {
                drawWall(i, j);
                drawDot(i, j);
            }
        }
    }

    // repaint part of screen (unit x,y and every surrounding units with
    // distance border
    public void repaintArea(int x, int y, int border) {
        g.setColor(Color.black);
        g.fillRect((int) ((x - border - this.x) * PIXEL_SCALE), (int) ((y
                - border - this.y) * PIXEL_SCALE), (2 * (border) + 1)
                * PIXEL_SCALE, (2 * (border) + 1) * PIXEL_SCALE);
        for (int i = x - border; i <= x + border; i++) {
            for (int j = y - border; j <= y + border; j++) {
                drawWall(i, j);
                drawDot(i, j);
            }
        }
    }

    public void drawDot(int x, int y) {
        if ((x < 0) || (y < 0)) {
            return;
        }
        if ((dots[x][y] != null) && isInScreen(x, y)) {
            dots[x][y].draw(this);
        }

    }

    public void moveGhost(RPObject object) {
        int x = object.getInt("x");
        int y = object.getInt("y");

        if (!isInScreen(x, y)) {
            return;
        }

        int imgCounter = object.getInt("imgCounter");
        if (imgCounter == 1) {
            object.put("imgCounter", 0);
        } else {
            object.put("imgCounter", imgCounter + 1);
        }

        int dir = object.getInt("dir");

        // standard collision check
        checkCollisionWithWall(object);

        // check collision with other ghosts
        boolean ghostcollision = false;
        for (RPObject ghost : Ghosts) {
            if (ghost != object) {
                switch (dir) {
                    case Constants.DIR_NORTH:
                        if ((ghost.getInt("x") == x)
                                && (ghost.getInt("y") == y - 1)) {
                            ghostcollision = true;
                        }
                        break;
                    case Constants.DIR_SOUTH:
                        if ((ghost.getInt("x") == x)
                                && (ghost.getInt("y") == y + 1)) {
                            ghostcollision = true;
                        }
                        break;
                    case Constants.DIR_EAST:
                        if ((ghost.getInt("x") == x + 1)
                                && (ghost.getInt("y") == y)) {
                            ghostcollision = true;
                        }
                        break;
                    case Constants.DIR_WEST:
                        if ((ghost.getInt("x") == x - 1)
                                && (ghost.getInt("y") == y)) {
                            ghostcollision = true;
                        }
                        break;
                }
            }
        }
        if (ghostcollision) {
            object.put("move", 0);
        }

        Vector<Sprite> sprite_Ghost;
        switch (object.getInt("color")) {
            case 0:
                sprite_Ghost = sprite_GhostR;
                break;
            case 1:
                sprite_Ghost = sprite_GhostG;
                break;
            case 2:
                sprite_Ghost = sprite_GhostR;
                break;
            default:
                sprite_Ghost = sprite_GhostG;
                break;
        }

        switch (dir) {
            case Constants.DIR_NORTH:
                draw(sprite_Ghost.get(imgCounter), g, x, y
                        - (object.getInt("move") / movePixelsPerFrame));
                break;
            case Constants.DIR_SOUTH:
                draw(sprite_Ghost.get((2 * dir) + imgCounter), g, x, y
                        + (object.getInt("move") / movePixelsPerFrame));
                break;
            case Constants.DIR_EAST:
                draw(sprite_Ghost.get((2 * dir) + imgCounter), g, x
                        + (object.getInt("move") / movePixelsPerFrame), y);
                break;
            case Constants.DIR_WEST:
                draw(sprite_Ghost.get((2 * dir) + imgCounter), g, x
                        - (object.getInt("move") / movePixelsPerFrame), y);
                break;
            case Constants.DIR_NONE:
                draw(sprite_Ghost.get(8 + imgCounter), g, x, y);
                break;
        }

    }

    private void checkCollisionWithWall(RPObject object) {
        int nextDir = object.getInt("nextdir");
        int x = object.getInt("x");
        int y = object.getInt("y");

        if (nextDir == Constants.DIR_NONE) {
            switch (object.getInt("dir")) {
                case Constants.DIR_NORTH:
                    if (walls[x][y - 1] > -1) {
                        object.put("dir", Constants.DIR_NONE);
                    }
                    break;
                case Constants.DIR_SOUTH:
                    if (walls[x][y + 1] > -1) {
                        object.put("dir", Constants.DIR_NONE);
                    }
                    break;
                case Constants.DIR_EAST:
                    if (walls[x + 1][y] > -1) {
                        object.put("dir", Constants.DIR_NONE);
                    }
                    break;
                case Constants.DIR_WEST:
                    if (walls[x - 1][y] > -1) {
                        object.put("dir", Constants.DIR_NONE);
                    }
                    break;
            }
        } else {
            boolean collision = false;
            switch (nextDir) {
                case Constants.DIR_NORTH:
                    if (walls[x][y - 1] > -1) {
                        collision = true;
                    }
                    break;
                case Constants.DIR_SOUTH:
                    if (walls[x][y + 1] > -1) {
                        collision = true;
                    }
                    break;
                case Constants.DIR_EAST:
                    if (walls[x + 1][y] > -1) {
                        collision = true;
                    }
                    break;
                case Constants.DIR_WEST:
                    if (walls[x - 1][y] > -1) {
                        collision = true;
                    }
                    break;
            }
            if (!collision) {
                object.put("dir", nextDir);
                object.put("nextdir", Constants.DIR_NONE);
            }
        }

    }

    public void setPlayerName(String name) {
        myPlayerName = name;
    }

    public String getPlayerName() {
        return myPlayerName;
    }

    public void setPlayer(RPObject object) {
        myPlayer = object;

    }

    public void addDot(RPObject object) {
        if (object.getInt("respawn") < 1) {
            int x = object.getInt("x");
            int y = object.getInt("y");
            if (object.get("type").equals(Constants.TYPE_DOT)) {
                dots[x][y] = new Dot(object);
            } else if (object.get("type").equals(Constants.TYPE_SUPERDOT)) {
                dots[x][y] = new Superdot(object);
            } else if (object.get("type").equals(Constants.TYPE_POWERPILL)) {
                dots[x][y] = new Powerpill(object);
            } else if (object.get("type").equals(Constants.TYPE_FRUIT)) {
                dots[x][y] = new Fruit(object);
            }

            dots[x][y].draw(this);
        } else {
            dots[object.getInt("x")][object.getInt("y")] = null;
        }
    }

    public void setPlayerGhostVector(Vector<RPObject> newPlayerVector,
            Vector<RPObject> newGhostVector) {
        Players = newPlayerVector;
        Ghosts = newGhostVector;
    }

    public void printChatText(String text) {
        if (ChatMessages.size() == 2) {
            ChatMessages.remove(0);
        }
        ChatMessages.add(text);

    }

    public RPObject getPlayer() {
        return myPlayer;
    }

    public boolean noScrollinLastTurn() {
        if (scrolledInLastTurn) {
            scrolledInLastTurn = false;
            return false;
        } else {
            return true;
        }
    }

    public void clear() {
        walls = new int[ww][wh];
        dots = new Dot[ww][wh];
        for (int i = 0; i < ww; i++) {
            for (int j = 0; j < wh; j++) {
                walls[i][j] = -1;
                dots[i][j] = null;
            }
        }
        zoneChangePoints.clear();

    }

    public void addZoneChange(ZoneChangePoint object) {
        zoneChangePoints.add(object);

    }

    public Vector<Sprite> getFruitsSprites() {
        return sprite_fruit;
    }

    public Sprite getDotSprite(int type_dot) {
        switch (type_dot) {
            case Dot.TYPE_SUPERDOT:
                return sprite_superdot;
            case Dot.TYPE_FRUIT:
                return sprite_fruit.get(0);
            case Dot.TYPE_POWERPILL:
                return sprite_powerpill;
            default:
                return sprite_dot;
        }
    }

    public Sprite getKillSprite(int i) {
        return sprite_EatenSprite.get(i);
    }

    public void addEatenSign(RPObject sign) {
        EatenSigns.add(new EatenSign(sign));
    }

    public void addScoreSign(RPObject sign) {
        ScoreSigns.add(new ScoreSign(sign));
    }

    public void removeEatenSign(RPObject object) {
        if (EatenSigns.size() == 1) {
            EatenSigns.clear();
        } else {
            Vector<EatenSign> deleteEatenSigns = new Vector<EatenSign>();
            for (EatenSign sign : EatenSigns) {
                if (sign.getRPObject() == object) {
                    deleteEatenSigns.add(sign);
                }
            }
            for (EatenSign sign : deleteEatenSigns) {
                EatenSigns.remove(sign);
            }
        }
    }

    public void removeScoreSign(RPObject object) {
        if (ScoreSigns.size() == 1) {
            ScoreSigns.clear();
        } else {
            Vector<ScoreSign> deleteScoreSigns = new Vector<ScoreSign>();
            for (ScoreSign sign : ScoreSigns) {
                if (sign.getRPObject() == object) {
                    deleteScoreSigns.add(sign);
                }
            }
            for (ScoreSign sign : deleteScoreSigns) {
                ScoreSigns.remove(sign);
            }
        }
    }
}
